home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / INDEX.PY < prev    next >
Encoding:
Python Source  |  1999-05-13  |  10.3 KB  |  338 lines

  1. ##############################################################################
  2. # Zope Public License (ZPL) Version 1.0
  3. # -------------------------------------
  4. # Copyright (c) Digital Creations.  All rights reserved.
  5. # This license has been certified as Open Source(tm).
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. # 1. Redistributions in source code must retain the above copyright
  10. #    notice, this list of conditions, and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. #    notice, this list of conditions, and the following disclaimer in
  13. #    the documentation and/or other materials provided with the
  14. #    distribution.
  15. # 3. Digital Creations requests that attribution be given to Zope
  16. #    in any manner possible. Zope includes a "Powered by Zope"
  17. #    button that is installed by default. While it is not a license
  18. #    violation to remove this button, it is requested that the
  19. #    attribution remain. A significant investment has been put
  20. #    into Zope, and this effort will continue if the Zope community
  21. #    continues to grow. This is one way to assure that growth.
  22. # 4. All advertising materials and documentation mentioning
  23. #    features derived from or use of this software must display
  24. #    the following acknowledgement:
  25. #      "This product includes software developed by Digital Creations
  26. #      for use in the Z Object Publishing Environment
  27. #      (http://www.zope.org/)."
  28. #    In the event that the product being advertised includes an
  29. #    intact Zope distribution (with copyright and license included)
  30. #    then this clause is waived.
  31. # 5. Names associated with Zope or Digital Creations must not be used to
  32. #    endorse or promote products derived from this software without
  33. #    prior written permission from Digital Creations.
  34. # 6. Modified redistributions of any form whatsoever must retain
  35. #    the following acknowledgment:
  36. #      "This product includes software developed by Digital Creations
  37. #      for use in the Z Object Publishing Environment
  38. #      (http://www.zope.org/)."
  39. #    Intact (re-)distributions of any official Zope release do not
  40. #    require an external acknowledgement.
  41. # 7. Modifications are encouraged but must be packaged separately as
  42. #    patches to official Zope releases.  Distributions that do not
  43. #    clearly separate the patches from the original work must be clearly
  44. #    labeled as unofficial distributions.  Modifications which do not
  45. #    carry the name Zope may be packaged in any form, as long as they
  46. #    conform to all of the clauses above.
  47. # Disclaimer
  48. #   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
  49. #   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50. #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  51. #   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
  52. #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  53. #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  54. #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  55. #   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  56. #   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  57. #   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  58. #   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  59. #   SUCH DAMAGE.
  60. # This software consists of contributions made by Digital Creations and
  61. # many individuals on behalf of Digital Creations.  Specific
  62. # attributions are listed in the accompanying credits file.
  63. ##############################################################################
  64.  
  65. """Simple column indices"""
  66. __version__='$Revision: 1.26 $'[11:-2]
  67.  
  68. from Globals import Persistent
  69. from BTree import BTree
  70. from intSet import intSet
  71. import operator
  72. from Missing import MV
  73. import string
  74.  
  75. ListType=type([])
  76. StringType=type('s')
  77.  
  78.  
  79. def nonEmpty(s):
  80.     "returns true if a non-empty string or any other (nonstring) type"
  81.     if type(s) is StringType:
  82.         if s: return 1
  83.         else: return 0
  84.     else:
  85.         return 1
  86.  
  87.  
  88. class Index(Persistent):
  89.     """Index object interface"""
  90.  
  91.     def __init__(self, data=None, schema=None, id=None,
  92.                  ignore_ex=None, call_methods=None):
  93.         """Create an index
  94.  
  95.         The arguments are:
  96.  
  97.           'data' -- a mapping from integer object ids to objects or
  98.           records,
  99.  
  100.           'schema' -- a mapping from item name to index into data
  101.           records.  If 'data' is a mapping to objects, then schema
  102.           should ne 'None'.
  103.  
  104.           'id' -- the name of the item attribute to index.  This is
  105.           either an attribute name or a record key.
  106.  
  107.         """
  108.     ######################################################################
  109.     # For b/w compatability, have to allow __init__ calls with zero args
  110.  
  111.         if not data==schema==id==ignore_ex==call_methods==None:
  112.             self._data = data
  113.             self._schema = schema
  114.             self.id = id
  115.             self.ignore_ex=ignore_ex
  116.             self.call_methods=call_methods
  117.             self._index = BTree()
  118.             
  119.             self._reindex()
  120.         else:
  121.             pass
  122.  
  123.     # for b/w compatability
  124.     _init = __init__
  125.  
  126.  
  127.     def dpHasUniqueValuesFor(self, name):
  128.         ' has unique values for column NAME '
  129.         if name == self.id:
  130.             return 1
  131.         else:
  132.             return 0
  133.  
  134.  
  135.     def dpUniqueValues(self, name=None, withLengths=0):
  136.         """\
  137.         returns the unique values for name
  138.  
  139.         if withLengths is true, returns a sequence of
  140.         tuples of (value, length)
  141.         """
  142.         if name is None:
  143.             name = self.id
  144.         elif name != self.id:
  145.             return []
  146.         if not withLengths: return tuple(
  147.             filter(nonEmpty,self._index.keys())
  148.             )
  149.         else: 
  150.             rl=[]
  151.             for i in self._index.keys():
  152.                 if not nonEmpty(i): continue
  153.                 else: rl.append((i, len(self._index[i])))
  154.             return tuple(rl)
  155.  
  156.  
  157.     def clear(self):
  158.         self._index = BTree()
  159.  
  160.  
  161.     def _reindex(self, start=0):
  162.         """Recompute index data for data with ids >= start."""
  163.  
  164.         index=self._index
  165.         get=index.get
  166.         
  167.         if not start: index.clear()
  168.  
  169.         id = self.id
  170.         if self._schema is None:
  171.             f=getattr
  172.         else:
  173.             f = operator.__getitem__
  174.             id = self._schema[id]
  175.  
  176.         for i,row in self._data.items(start):
  177.             k=f(row,id)
  178.  
  179.             if k is None or k == MV: continue
  180.  
  181.             set=get(k)
  182.             if set is None: index[k] = set = intSet()
  183.             set.insert(i)
  184.  
  185.  
  186.     def index_item(self, i, obj=None):
  187.         """Recompute index data for data with ids >= start."""
  188.         index = self._index
  189.         id = self.id
  190.         if (self._schema is None) or (obj is not None):
  191.             f = getattr
  192.         else:
  193.             f = operator.__getitem__
  194.             id = self._schema[id]
  195.  
  196.         if obj is None:
  197.             obj = self._data[i]
  198.  
  199.         try:    k=f(obj, id)
  200.         except: return
  201.         if self.call_methods:
  202.             k=k()
  203.         if k is None or k == MV:
  204.             return
  205.  
  206.         set = index.get(k)
  207.         if set is None: index[k] = set = intSet()
  208.         set.insert(i)
  209.  
  210.  
  211.     def unindex_item(self, i, obj=None):
  212.         """Recompute index data for data with ids >= start."""
  213.         index = self._index
  214.         id = self.id
  215.         if self._schema is None:
  216.             f = getattr
  217.         else:
  218.             f = operator.__getitem__
  219.             id = self._schema[id]
  220.         if obj is None:
  221.             obj = self._data[i]
  222.  
  223.         try:    k=f(obj, id)
  224.         except: return
  225.         if self.call_methods:
  226.             k=k()
  227.         if k is None or k == MV:
  228.             return
  229.  
  230.         set = index.get(k)
  231.         if set is not None: set.remove(i)
  232.  
  233.  
  234.     def _apply_index(self, request, cid=''): 
  235.         """Apply the index to query parameters given in the argument,
  236.         request
  237.  
  238.         The argument should be a mapping object.
  239.  
  240.         If the request does not contain the needed parameters, then
  241.         None is returned.
  242.  
  243.         If the request contains a parameter with the name of the
  244.         column + '_usage', it is sniffed for information on how to
  245.         handle applying the index.
  246.  
  247.         Otherwise two objects are returned.  The first object is a
  248.         ResultSet containing the record numbers of the matching
  249.         records.  The second object is a tuple containing the names of
  250.         all data fields used.
  251.  
  252.         """
  253.         id = self.id              #name of the column
  254.  
  255.         cidid = "%s/%s" % (cid,id)
  256.         has_key = request.has_key
  257.         if has_key(cidid): keys = request[cidid]
  258.         elif has_key(id): keys = request[id]
  259.         else: return None
  260.  
  261.         if type(keys) is not ListType: keys=[keys]
  262.         index = self._index
  263.         r = None
  264.         anyTrue = 0
  265.         opr = None
  266.  
  267.         if request.has_key(id+'_usage'):
  268.             # see if any usage params are sent to field
  269.             opr=string.split(string.lower(request[id+"_usage"]),':')
  270.             opr, opr_args=opr[0], opr[1:]
  271.  
  272.         if opr=="range":
  273.             if 'min' in opr_args: lo = min(keys)
  274.             else: lo = None
  275.             if 'max' in opr_args: hi = max(keys)
  276.             else: hi = None
  277.  
  278.             anyTrue=1
  279.             try:
  280.                 if hi: setlist = index.items(lo,hi)
  281.                 else:  setlist = index.items(lo)
  282.                 for k,set in setlist:
  283.                     if r is None: r = set
  284.                     else: r = r.union(set)
  285.             except KeyError: pass
  286.         else:           #not a range
  287.             get = index.get
  288.             for key in keys:
  289.                 if key: anyTrue = 1
  290.                 set=get(key)
  291.                 if set is not None:
  292.                     if r is None: r = set
  293.                     else: r = r.union(set)
  294.  
  295.         if r is None:
  296.             if anyTrue: r=intSet()
  297.             else: return None
  298.  
  299.         return r, (id,)
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
  310.  
  311.  
  312.  
  313.  
  314.  
  315.  
  316.  
  317.